package com.xxgc.cloud.common.redis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @program: SpringCloudStudy
 * @description:
 * @author: Shijiayi
 * @create: 2022-12-13 16:18
 **/
@Slf4j
@Component
public class RedisUtil {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;



    //################################################## 通用操作 start #################################################
    /**
     * <p>删除单个key值</p>
     *
     * @author hkl
     * @date 2022/9/15
     */
    public boolean delete(String key) {
        try {
            redisTemplate.delete(key);
            return true;
        } catch (Exception e) {
            log.error("RedisUtil method delete Exception：", e);
        }
        return false;
    }

    /**
     * <p>批量删除key值</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public boolean delete(List<String> keys) {
        try {
            redisTemplate.delete(keys);
            return true;
        } catch (Exception e) {
            log.error("RedisUtil method delete Exception：", e);
        }
        return false;
    }

    /**
     * <p>把key设置过期时间，默认秒</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        try {
            if (ObjectUtil.isNull(timeUnit)) {
                timeUnit = TimeUnit.SECONDS;
            }
            //设置过期时间
            redisTemplate.expire(key, time, timeUnit);
            return true;
        } catch (Exception e) {
            log.error("RedisUtil method expire Exception：", e);
        }
        return false;
    }

    /**
     * <p>设置到指定日期过期</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Boolean expireAt(String key, Date date) {
        return redisTemplate.expireAt(key, date);
    }

    /**
     * <p>获取匹配的key集合，返回一个Set集合</p>
     * <p>例如：获取所有的key【redisTemplate.keys("*")】，获取带前缀的key【redisTemplate.keys(prefix.concat("*"))】</p>
     *
     * @param pattern 表达式(*、pro_*等)，支持模糊匹配
     * @author hkl
     * @date 2022/11/12
     */
    public Set<String> getPatternKey(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * <p>对key重命名</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public boolean renameKey(String oldKey, String newKey) {
        try {
            redisTemplate.rename(oldKey, newKey);
            return true;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * <p>返回key对应值的类型</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public DataType getKeyType(String key) {
        return redisTemplate.type(key);
    }

    /**
     * <p>如果旧key存在，将旧key改为新key</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Boolean renameOldKeyIfAbsent(String oldKey, String newKey) {
        try {
            if(redisTemplate.hasKey(oldKey)){
                return redisTemplate.renameIfAbsent(oldKey, newKey);
            }
        } catch (Exception e) {
            log.error("renameOldKeyIfAbsent出现异常：{}", e.getMessage());
            throw new RuntimeException(e);
        }
        return false;
    }

    /**
     * <p>从keys中随机获取一个key</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public String getRandomKey() {
        return redisTemplate.randomKey();
    }

    /**
     * <p>返回key所对应的剩余过期时间</p>
     * <p>-1为没有过期时间</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * <p>返回key所对应的剩余过期时间，并指定时间单位</p>
     * <p>-1为没有过期时间</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long getExpire(String key, TimeUnit unit) {
        return redisTemplate.getExpire(key, unit);
    }

    /**
     * <p>将有过期时间的key持久化保存，改为-1</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Boolean persistKey(String key) {
        return redisTemplate.persist(key);
    }

    /**
     * <p>将当前数据库的key移动到指定的redis数据库中</p>
     * <p>同一个数据库下不可移动，会报错</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Boolean moveToDbIndex(String key, int dbIndex) {
        return redisTemplate.move(key, dbIndex);
    }

    /**
     * <p>判断 key 是否存在</p>
     *
     * @author hkl
     * @date 2022/9/15
     */
    public Boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            log.error("RedisUtil method hasKey Exception：", e);
        }
        return false;
    }
    //################################################## 通用操作 end #################################################






    //################################################## String类型 start #################################################

    /**
     * <p>根据key获取value字符串</p>
     *
     * @author hkl
     * @date 2022/9/15
     */
    public String getStr(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * <p>返回key中字符串的截取字符，包含start、end索引</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public String getStr(String key, long start, long end) {
        return stringRedisTemplate.opsForValue().get(key, start, end);
    }

    /**
     * <p>获取多个key对应的值</p>
     *
     * @return
     * @author hkl
     * @date 2022/11/12
     */
    public List<String> multiGetStr(List<String> keys) {
        return stringRedisTemplate.opsForValue().multiGet(keys);
    }

    /**
     * <p>获取key对应的值长度</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long sizeStr(String key) {
        return stringRedisTemplate.opsForValue().size(key);
    }

    /**
     * <p>把字符串写入缓存（key有就覆盖没有就添加），key为键、value为值</p>
     *
     * @author hkl
     * @date 2022/9/15
     */
    public boolean setStr(String key, String value) {
        try {
            stringRedisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error("RedisUtil method set Exception：", e);
        }
        return false;
    }

    /**
     * <p>把字符串写入缓存（key有就覆盖没有就添加），具有时效性(默认为秒)</p>
     *
     * @author hkl
     * @date 2022/9/15
     */
    public boolean setStr(String key, String value, long time, TimeUnit timeUnit) {
        try {
            if (ObjectUtil.isNull(timeUnit)) {
                timeUnit = TimeUnit.SECONDS;
            }
            stringRedisTemplate.opsForValue().set(key, value, time, timeUnit);
            return true;
        } catch (Exception e) {
            log.error("RedisUtil method set Exception：", e);
        }
        return false;
    }

    /**
     * <p>当key不存在则添加成功返回true，否则不做动作返回false</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Boolean setIfAbsentStr(String key, String value) {
        return stringRedisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * <p>写入多个key、value到缓存，字符串类型</p>
     * <p>key存在则更新，不存在则添加</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public void multiSetStr(Map<String, String> map) {
        stringRedisTemplate.opsForValue().multiSet(map);
    }

    /**
     * <p>写入多个key、value到缓存，字符串类型</p>
     * <p>当全部key都不存在则添加成功返回true，否则不做动作返回false</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Boolean multiSetIfAbsentStr(Map<String, String> map) {
        return stringRedisTemplate.opsForValue().multiSetIfAbsent(map);
    }

    /**
     * <p>当key存在获取key当前的值，然后把值更新为value，否则添加key、value</p>
     *
     * @param
     * @author hkl
     * @date 2022/9/15
     */
    public String getAndSetStr(String key, String value) {
        try {
            return stringRedisTemplate.opsForValue().getAndSet(key, value);
        } catch (Exception e) {
            log.error("RedisUtil method getAndSet Exception：", e);
        }
        return "";
    }

    /**
     * <p>当key存在，在key对应的原有值的基础上追加value到末尾，否则添加key、value</p>
     * <p>返回追加后的值长度</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public boolean appendStr(String key, String value) {
        try {
            Integer append = stringRedisTemplate.opsForValue().append(key, value);
            return (ObjectUtil.isNotNull(append) && append > 0);
        } catch (Exception e) {
            log.error("RedisUtil method append Exception：", e);
        }
        return false;
    }

    /**
     * <p>以增量方式获取key对应的数值，key不存在则添加，默认值是1，默认增量因子是1</p>
     *
     * @author hkl
     * @date 2022/11/15
     */
    public Long increment(String key) {
        return stringRedisTemplate.opsForValue().increment(key);
    }

    /**
     * <p>以增量方式获取key对应的数值，increment是增量因子，返回增量之后的结果</p>
     * <p>key存在则递增，不存在则添加key、increment</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long increment(String key, long increment) {
        return stringRedisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * <p>以增量方式获取key对应的数值，increment是增量因子，返回增量之后的结果</p>
     * <p>key存在则递增，不存在则添加key、increment</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Double increment(String key, double increment) {
        return stringRedisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * <p>以减量方式获取key对应的数值，key不存在则添加，默认值是-1，默认减量因子是1</p>
     *
     * @author hkl
     * @date 2022/11/15
     */
    public Long decrement(String key) {
        return stringRedisTemplate.opsForValue().decrement(key);
    }

    /**
     * <p>以减量方式获取key对应的数值，key不存在则添加，减量因子是decrement</p>
     *
     * @author hkl
     * @date 2022/11/15
     */
    public Long decrement(String key, long decrement) {
        return stringRedisTemplate.opsForValue().decrement(key, decrement);
    }

    /**
     * <p>对key所储存的字符串值，获取指定偏移量上的位(bit)</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Boolean getBit(String key, Long offset) {
        return stringRedisTemplate.opsForValue().getBit(key, offset);
    }


    /**
     * <p>加锁</p>
     *
     * @author hkl
     * @date 2022/9/15
     */
    public boolean lock(String key, String value, long time) {
        try {
            Boolean setIfAbsentRes = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
            if (setIfAbsentRes) {
                //设置成功，加锁设置过期时间
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
                return true;
            }
        } catch (Exception e) {
            log.error("RedisUtil method setIfAbsent Exception:", e);
        }
        return false;
    }

    /**
     * <p>释放锁</p>
     *
     * @author hkl
     * @date 2022/9/15
     */
    public boolean unlock(String key, String value) {
        try {
            String res = stringRedisTemplate.opsForValue().get(key);
            if (value.equals(res)) {
                redisTemplate.delete(key);
                return true;
            }
        } catch (Exception e) {
            log.error("RedisUtil method unlock Exception:", e);
        }
        return false;
    }
    //################################################## String类型 end #################################################






    //################################################## List类型 start #################################################

    /**
     * <p>在key列表最左索引处(最前面)，添加一个元素</p>
     * <p>key不存在则添加key，增量添加元素(List是可重复列表)</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long leftPushList(String key, Object value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * <p>在key列表最左索引处(最前面)，添加多个元素</p>
     * <p>key不存在则添加key，增量添加元素(List是可重复列表)</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long leftPushAllList(String key, List<Object> values) {
        return redisTemplate.opsForList().leftPushAll(key, values);
    }

    /**
     * <p>在key列表中的 pivot 元素前面添加value元素</p>
     * <p>pivot元素不存在则不添加</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long leftPushList(String key, Object pivot, Object value) {
        return redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * <p>key列表存在的时候，在列表最左边添加一个元素，否则不做动作</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long leftPushIfPresentList(String key, Object value) {
        return redisTemplate.opsForList().leftPushIfPresent(key, value);
    }

    /**
     * <p>按照先进先出的顺序添加，单个元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long rightPushList(String key, Object value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * <p>按照先进先出的顺序添加，多个元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long rightPushAllList(String key, List<Object> values) {
        return redisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * <p>按照先进先出的顺序在pivot元素右边添加，单个元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long rightPushList(String key, Object pivot, Object value) {
        return redisTemplate.opsForList().rightPush(key, pivot, value);
    }

    /**
     * <p>key列表存在的时候，在列表最左边添加一个元素，否则不做动作</p>
     *
     * @author hkl
     * @date 2022/11/16
     */
    public Long rightPushIfPresentList(String key, String value){
        return redisTemplate.opsForList().rightPushIfPresent(key, value);
    }

    /**
     * <p>添加指定索引的元素</p>
     * <p>覆盖指定索引已有元素。指定索引不可越界，会报错</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public void setList(String key, long index, Object value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * <p>根据索引获取key对应列表中的元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Object indexList(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * <p>最好不要范围越界</p>
     * <p>获取key对应列表指定范围内的元素（start开始位置、必须大于等于0，end结束位置、可以为负数-1）</p>
     * <p>包括startIndex、endIndex元素，startIndex小于0返回空，endIndex为-1返回所有元素</p>
     * <p>(0, -1)返回所有元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public List<Object> rangeList(String key, long startIndex, long endIndex) {
        return redisTemplate.opsForList().range(key, startIndex, endIndex);
    }

    /**
     * <p>获取并移除key对应列表中最左边第一个元素</p>
     * <p>如果列表中没有元素会阻塞列表，直到等待超时或有元素为止</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Object leftPopList(String key, long timeout, TimeUnit timeUnit) {
        if (ObjectUtil.isNull(timeUnit)) {
            timeUnit = TimeUnit.SECONDS;
        }
        return redisTemplate.opsForList().leftPop(key, timeout, timeUnit);
    }

    /**
     * <p>获取并移除key对应列表中最右边第一个元素</p>
     * <p>如果列表中没有元素会阻塞列表，直到等待超时或有元素为止</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Object rightPopList(String key, long timeout, TimeUnit timeUnit) {
        if (ObjectUtil.isNull(timeUnit)) {
            timeUnit = TimeUnit.SECONDS;
        }
        return redisTemplate.opsForList().rightPop(key, timeout, timeUnit);
    }

    /**
     * <p>从sourceKey列表中取出最后一个元素，把这个元素添加到destinationKey(不存在则新添加)列表中的最左边第一个</p>
     * <p>如果列表中没有元素会阻塞列表，直到等待超时或有元素为止</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Object rightPopAndLeftPushList(String sourceKey, String destinationKey, long timeout, TimeUnit timeUnit) {
        if (ObjectUtil.isNull(timeUnit)) {
            timeUnit = TimeUnit.SECONDS;
        }
        return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey, timeout, timeUnit);
    }

    /**
     * <p>移除key列表中值等于value的元素，这里的index是数量，不是索引</p>
     * <p>index=0，删除所有值等于value的元素; index>0，从最左边开始删除第index个值等于value的元素; index<0, 从最右边开始删除第index个值等于value的元素</p>
     * <p>返回被删除元素的数量</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long removeList(String key, long index, Object value) {
        return redisTemplate.opsForList().remove(key, index, value);
    }

    /**
     * <p>获取key列表的长度</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long sizeList(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * <p>将列表进行裁剪，移除掉start到end之间的元素(包括start不包括end)</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public void trimList(String key, long start, long end) {
        redisTemplate.opsForList().trim(key, start, end);
    }
    //################################################## List类型 end #################################################






    //################################################## Set类型 start #################################################

    /**
     * <p>向key对应的值set集合中添加元素</p>
     * <p>如果添加的元素与集合中的元素重复则不添加，不重复的元素则添加</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public boolean addSet(String key, Object... values) {
        boolean result = false;
        try {
            Long add = redisTemplate.opsForSet().add(key, values);
            result = true;
        } catch (Exception e) {
            log.error("RedisUtil method add Exception：", e);
        }
        return result;
    }

    /**
     * <p>向key对应的值set集合中添加元素</p>
     * <p>如果添加的元素与集合中的元素重复则不添加，不重复的元素则添加</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public boolean addSetByList(String key, List<Object> objects) {
        try {
            if (CollUtil.isEmpty(objects)) {
                log.info("objects is null!");
                return false;
            }
            redisTemplate.opsForSet().add(key, ArrayUtil.toArray(objects, Object.class));
            return true;
        } catch (Exception e) {
            log.error("RedisUtil method add Exception：", e);
        }
        return false;
    }

    /**
     * <p>移除key对应的值set集合中一个或多个元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public boolean removeSet(String key, Object... values) {
        boolean result = false;
        try {
            Long removeRes = redisTemplate.opsForSet().remove(key, values);
            if (ObjectUtil.isNotNull(removeRes) && removeRes > 0) {
                result = true;
            }
        } catch (Exception e) {
            log.error("RedisUtil method remove Exception：", e);
        }
        return result;
    }

    /**
     * <p>删除并且返回一个随机的元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Object popSet(String key) {
        return redisTemplate.opsForSet().pop(key);
    }

    /**
     * <p>获取Set集合的大小</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long sizeSet(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * <p>校验key对应的Set集合是否存在该value</p>
     *
     * @author hkl
     * @date 2022/9/16
     */
    public Boolean isMemberSet(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * <p>获取集合的所有元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Set<Object> membersSet(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * <p>随机获取集合中的一个元素</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Object randomMemberSet(String key) {
        return redisTemplate.opsForSet().randomMember(key);
    }

//    /**
//     * <p>获取两个集合的交集（key对应的Set集合和otherKey对应的Set集合，二者集合的交集）</p>
//     *
//     * @author hkl
//     * @date 2022/11/12
//     */
//    public Set<Object> intersect(String key, String otherKey){
//        return redisTemplate.opsForSet().intersect(key, otherKey);
//    }

    /**
     * <p>获取key对应的集合与otherKeyList对应的集合的交集</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Set<Object> intersectSet(String key, List<String> otherKeyList) {
        return redisTemplate.opsForSet().intersect(key, otherKeyList);
    }

//    /**
//     * <p>key集合与otherKey集合的交集存储到destKey对应的集合中</p>
//     *
//     * @author hkl
//     * @date 2022/11/12
//     */
//    public Long intersectAndStore(String key, String otherKey, String destKey) {
//        return redisTemplate.opsForSet().intersectAndStore(key, otherKey, destKey);
//    }

    /**
     * <p>key对应的集合与otherKeyList对应的集合的交集存储到destKey对应的集合中</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long intersectAndStoreSet(String key, List<String> otherKeyList, String destKey) {
        return redisTemplate.opsForSet().intersectAndStore(key, otherKeyList, destKey);
    }

    /**
     * <p>获取key对应的集合与otherKeyList对应的集合的并集</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Set<Object> unionSet(String key, List<String> otherKeyList) {
        return redisTemplate.opsForSet().union(key, otherKeyList);
    }

    /**
     * <p>key对应集合与otherKeyList对应集合的并集存储到destKey对应的集合中</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long unionAndStoreSet(String key, List<String> otherKeyList, String destKey) {
        return redisTemplate.opsForSet().unionAndStore(key, otherKeyList, destKey);
    }

    /**
     * <p>获取两个或多个集合的差集</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Set<Object> differenceSet(String key, List<String> otherKeyList) {
        return redisTemplate.opsForSet().difference(key, otherKeyList);
    }

    /**
     * <p>两个或多个集合的差集存储到destKey对应的集合中</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Long differenceAndStoreSet(String key, List<String> otherKeyList, String destKey) {
        return redisTemplate.opsForSet().differenceAndStore(key, otherKeyList, destKey);
    }

    /**
     * <p>遍历set类似于Interator(ScanOptions.NONE为显示所有的)</p>
     *
     * @author hkl
     * @date 2022/11/12
     */
    public Cursor<Object> scanSet(String key, ScanOptions options) {
        return redisTemplate.opsForSet().scan(key, options);
    }
    //################################################## Set类型 end #################################################






    //################################################## Hash类型 start #################################################
    /**
     * <p>获取key对应的Map中小key对应的值，没有则返回null</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Object getHash(String key, Object hashKey){
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * <p>获取key对应的完整Map集合</p>
     *
     * @author hkl
     * @date 2022/11/13
     * @param
     * @return
     */
    public Map<Object, Object> entriesHash(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * <p>在key对应的Map中添加键hashKey和值value</p>
     * <p>hashKey存在则更新，不存在则添加</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public void putHash(String key, Object hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * <p>在key下，以Map集合的形式添加键值</p>
     * <p>Map中的小hashKey存在则更新，不存在则添加</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public void putAllHash(String key, Map<String, Object> maps) {
        redisTemplate.opsForHash().putAll(key, maps);
    }

    /**
     * <p>在key对应的Map中，当hashKey不存在则添加键值返回true，存在则不做动作返回false</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Boolean putIfAbsentHash(String key, Object hashKey, Object value) {
        return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    }

    /**
     * <p>在key对应的Map中，删除一个或者多个小hashKey，小hashKey不存在也不会报错</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Long deleteHash(String key, Object... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * <p>查看key对应的Map中，是否存在小hashKey</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Boolean hasKeyHash(String key, Object hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * <p>增量方式获取key对应的Map集合中hashKey键的整数值，增量因子是increment</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Long incrementHash(String key, Object hashKey, long increment) {
        return redisTemplate.opsForHash().increment(key, hashKey, increment);
    }

    /**
     * <p>获取key对应的Map集合中所有键字段</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Set<Object> keysHash(String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * <p>获取key对应的Map集合中键数量</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Long sizeHash(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    /**
     * <p>获取key对应的Map集合中所有的值</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public List<Object> valuesHash(String key) {
        return redisTemplate.opsForHash().values(key);
    }

    /**
     * <p>在key对应的Map集合中，获取多个小hashKey的值</p>
     *
     * @author hkl
     * @date 2022/11/14
     */
    public List<Object> multiGetHash(String key, List<Object> hashKeys) {
        return redisTemplate.opsForHash().multiGet(key, hashKeys);
    }

    /**
     * <p>获取key对应的Map集合中小hashKey对应值的长度</p>
     * <p>因为多了存储值多了引号，所以长度比预期多2个单位</p>
     *
     * @author hkl
     * @date 2022/11/14
     */
    public Long lengthOfValueHash(String key, String hashKey) {
        return redisTemplate.opsForHash().lengthOfValue(key, hashKey);
    }

    /**
     * <p>匹配获取键值对，ScanOptions.NONE为获取全部键对</p>
     *
     * @author hkl
     * @date 2022/11/13
     */
    public Cursor<Map.Entry<Object, Object>> scanHash(String key, ScanOptions options) {
        return redisTemplate.opsForHash().scan(key, options);
    }

    //################################################## Hash类型 end ##################################################















    //################################################## 公用验证区域 start ##################################################
    public void putAllHashBound(String key, Map<String, Object> map){
        redisTemplate.boundHashOps(key).putAll(map);
        //redisTemplate.boundHashOps(key).hasKey()
    }
    //################################################## 公用验证区域 end ####################################################

}
